/**
 * $Id$
 */
package jm.lib.collections.map;

import java.util.LinkedHashMap;
import java.util.Map;

import jm.lib.common.Transformer;

/**
 * @author Jiming Liu
 *
 */
public class CaseInsensitiveLinkedMap<V> extends LinkedHashMap<String, V> {
    private static final long serialVersionUID = 2132452377366228817L;
    
    // ----------------------------------------------------------- Constructors
    
    /**
     * Construct a an empty map.
     */
    public CaseInsensitiveLinkedMap() {
        super();
    }
    
    /**
     * Construct an empty map with the specified capacity.
     *
     * @param capacity The initial capacity of the empty map
     */
    public CaseInsensitiveLinkedMap(int capacity) {
        super(capacity);
    }
    
    /**
     * Construct an empty map with the specified capacity and load factor.
     *
     * @param capacity The initial capacity of the empty map
     * @param factor The load factor of the new map
     */
    public CaseInsensitiveLinkedMap(int capacity, float factor) {
        super(capacity, factor);
    }
    
    /**
     * Construct a new map with the same mappings as the specified map.
     *
     * @param map The map whose mappings are to be copied
     */
    public CaseInsensitiveLinkedMap(Map<String,V> map) {
        super(map);
    }
    
    /**
     * Construct a new map with the same mappings as the specified map.
     *
     * @param map The map whose mappings are to be copied
     * @param asBase Use <code>map</code> as the base map to contain data. If using,
     * this map will have the feature that base <code>map</code> have,
     * such as concurrent
     */
//    public CaseInsensitiveLinkedMap(Map<String,V> map, boolean asBase) {
//
//      super();
//        if(asBase){
//            this.map = map;
//        }else{
//            this.map = new HashMap<String,V>(map.size ());
//            MapUtil.transformKey (map, t, this.map);
//        }
//
//    }
//
    
    // --------------------------------------------------------- Public Methods
    
    /**
     * Return <code>true</code> if this map contains a mapping for the
     * specified key.
     *
     * @param key Key to be searched for
     */
    public boolean containsKey(Object key) {
        return super.containsKey(key.toString().toLowerCase());
    }
    
    /**
     * Return the value to which this map maps the specified key.  Returns
     * <code>null</code> if the map contains no mapping for this key, or if
     * there is a mapping with a value of <code>null</code>.  Use the
     * <code>containsKey()</code> method to disambiguate these cases.
     *
     * @param key Key whose value is to be returned
     */
    public V get(Object key) {
        return super.get(key.toString().toLowerCase());
    }
    
    /**
     * Associate the specified value with the specified key in this map.
     * If the map previously contained a mapping for this key, the old
     * value is replaced and returned.
     *
     * @param key The key with which the value is to be associated
     * @param value The value to be associated with this key
     */
    public V put(String key, V value) {
        return super.put(key.toLowerCase(), value);
    }
    
    /**
     * Copy all of the mappings from the specified map to this one, replacing
     * any mappings with the same keys.
     *
     * @param in Map whose mappings are to be copied
     */
    @SuppressWarnings("unchecked")
	public void putAll(Map<? extends String, ? extends V> in) {
    	for(Map.Entry<? extends String, ? extends V> entry : in.entrySet()) {
    		this.put(entry.getKey().toLowerCase(), entry.getValue());
    	}
    }
    
    /**
     * Remove any mapping for this key, and return any previously
     * mapped value.
     *
     * @param key Key whose mapping is to be removed
     */
    public V remove(Object key) {
        return super.remove(key.toString().toLowerCase());
    }

    public String toString() {
        return super.toString();
    }
    
    static class LowercaseTransformer implements Transformer<String> {
        final public Object transform(String o) {
            return o.toLowerCase();
        }
    }

}
